// 认证相关路由
import { Router } from 'express'
import bcrypt from 'bcryptjs'
import Joi from 'joi'
import { prisma } from '../lib/prisma'
import { JWTManager } from '../lib/jwt'
import { CacheManager } from '../lib/memory-cache'
import { asyncHandler, createError } from '../middleware/error-handler'
import { authenticate } from '../middleware/auth'

const router = Router()

// 验证模式
const registerSchema = Joi.object({
  email: Joi.string().email().required().messages({
    'string.email': '请输入有效的邮箱地址',
    'any.required': '邮箱是必填项'
  }),
  password: Joi.string().min(6).max(50).required().messages({
    'string.min': '密码至少需要6个字符',
    'string.max': '密码不能超过50个字符',
    'any.required': '密码是必填项'
  }),
  nickname: Joi.string().max(50).optional().messages({
    'string.max': '昵称不能超过50个字符'
  })
})

const loginSchema = Joi.object({
  email: Joi.string().email().required().messages({
    'string.email': '请输入有效的邮箱地址',
    'any.required': '邮箱是必填项'
  }),
  password: Joi.string().required().messages({
    'any.required': '密码是必填项'
  })
})

const refreshSchema = Joi.object({
  refreshToken: Joi.string().required().messages({
    'any.required': '刷新令牌是必填项'
  })
})

// 用户注册
router.post('/register', asyncHandler(async (req, res) => {
  // 验证请求数据
  const { error, value } = registerSchema.validate(req.body)
  if (error) {
    throw createError.badRequest(error.details[0].message)
  }

  const { email, password, nickname } = value

  // 检查邮箱是否已存在
  const existingUser = await prisma.user.findUnique({
    where: { email }
  })

  if (existingUser) {
    throw createError.conflict('该邮箱已被注册')
  }

  // 加密密码
  const saltRounds = 12
  const passwordHash = await bcrypt.hash(password, saltRounds)

  // 创建用户
  const user = await prisma.user.create({
    data: {
      email,
      passwordHash,
      profile: {
        create: {
          nickname: nickname || email.split('@')[0]
        }
      },
      settings: {
        create: {}
      }
    },
    select: {
      id: true,
      email: true,
      emailVerified: true,
      createdAt: true
    }
  })

  // 生成令牌对
  const tokens = JWTManager.generateTokenPair({
    userId: user.id,
    email: user.email
  })

  // 存储刷新令牌
  await JWTManager.storeRefreshToken(user.id, tokens.refreshToken)

  res.status(201).json({
    message: '注册成功',
    user,
    tokens
  })
}))

// 用户登录
router.post('/login', asyncHandler(async (req, res) => {
  // 验证请求数据
  const { error, value } = loginSchema.validate(req.body)
  if (error) {
    throw createError.badRequest(error.details[0].message)
  }

  const { email, password } = value

  // 查找用户
  const user = await prisma.user.findUnique({
    where: { email },
    select: {
      id: true,
      email: true,
      passwordHash: true,
      emailVerified: true,
      createdAt: true
    }
  })

  if (!user) {
    throw createError.unauthorized('邮箱或密码错误')
  }

  // 验证密码
  const isPasswordValid = await bcrypt.compare(password, user.passwordHash)
  if (!isPasswordValid) {
    throw createError.unauthorized('邮箱或密码错误')
  }

  // 生成令牌对
  const tokens = JWTManager.generateTokenPair({
    userId: user.id,
    email: user.email
  })

  // 存储刷新令牌
  await JWTManager.storeRefreshToken(user.id, tokens.refreshToken)

  // 返回用户信息（不包含密码）
  const { passwordHash, ...userInfo } = user

  res.json({
    message: '登录成功',
    user: userInfo,
    tokens
  })
}))

// 刷新令牌
router.post('/refresh', asyncHandler(async (req, res) => {
  // 验证请求数据
  const { error, value } = refreshSchema.validate(req.body)
  if (error) {
    throw createError.badRequest(error.details[0].message)
  }

  const { refreshToken } = value

  // 验证刷新令牌
  const payload = JWTManager.verifyRefreshToken(refreshToken)
  if (!payload) {
    throw createError.unauthorized('无效的刷新令牌')
  }

  // 检查令牌是否在数据库中
  const isValid = await JWTManager.validateRefreshToken(refreshToken)
  if (!isValid) {
    throw createError.unauthorized('刷新令牌已失效')
  }

  // 检查用户是否存在
  const user = await prisma.user.findUnique({
    where: { id: payload.userId },
    select: {
      id: true,
      email: true,
      emailVerified: true
    }
  })

  if (!user) {
    throw createError.unauthorized('用户不存在')
  }

  // 生成新的令牌对
  const newTokens = JWTManager.generateTokenPair({
    userId: user.id,
    email: user.email
  })

  // 撤销旧的刷新令牌
  await JWTManager.revokeRefreshToken(refreshToken)

  // 存储新的刷新令牌
  await JWTManager.storeRefreshToken(user.id, newTokens.refreshToken)

  res.json({
    message: '令牌刷新成功',
    tokens: newTokens
  })
}))

// 用户登出
router.post('/logout', authenticate, asyncHandler(async (req, res) => {
  const refreshToken = req.body.refreshToken

  if (refreshToken) {
    // 撤销指定的刷新令牌
    await JWTManager.revokeRefreshToken(refreshToken)
  } else {
    // 撤销用户的所有刷新令牌
    await JWTManager.revokeAllUserTokens(req.user!.id)
  }

  res.json({
    message: '登出成功'
  })
}))

// 撤销所有会话
router.post('/logout-all', authenticate, asyncHandler(async (req, res) => {
  await JWTManager.revokeAllUserTokens(req.user!.id)

  res.json({
    message: '已登出所有设备'
  })
}))

// 获取当前用户信息
router.get('/me', authenticate, asyncHandler(async (req, res) => {
  const userId = req.user!.id
  
  // 尝试从缓存获取
  const cacheKey = CacheManager.getUserCacheKey(userId, 'profile')
  let userInfo = await CacheManager.get(cacheKey)
  
  if (!userInfo) {
    userInfo = await prisma.user.findUnique({
      where: { id: userId },
      select: {
        id: true,
        email: true,
        emailVerified: true,
        createdAt: true,
        profile: {
          select: {
            nickname: true,
            avatarUrl: true
          }
        },
        settings: {
          select: {
            theme: true,
            searchEngine: true,
            backgroundType: true,
            backgroundValue: true,
            showBookmarks: true,
            showWeather: true,
            showTime: true,
            language: true
          }
        }
      }
    })
    
    if (userInfo) {
      // 缓存5分钟
      await CacheManager.set(cacheKey, userInfo, 300)
    }
  }

  if (!userInfo) {
    throw createError.notFound('用户不存在')
  }

  res.json({
    user: userInfo
  })
}))

// 验证令牌有效性
router.get('/verify', authenticate, asyncHandler(async (req, res) => {
  res.json({
    valid: true,
    user: {
      id: req.user!.id,
      email: req.user!.email
    }
  })
}))

export { router as authRoutes }